﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using LinFu.IoC;
using LinFu.IoC.Configuration;
using LinFu.IoC.Interfaces;
using System.Linq;
using LinFu.Proxy;
using LinFu.Proxy.Interfaces;
using LinFu.Reflection;

namespace CoreEx.Services
{
    public static class ServiceLocator
    {
        private static IServiceContainer _serviceContainer;
            
        static ServiceLocator()
        {
            try
            {
                InitializeContainer();
            }
            
            catch(ReflectionTypeLoadException ex)
            {
                Trace.TraceError(ex.ToString());
                foreach (var loaderException in ex.LoaderExceptions)
                {
                    Trace.TraceError(loaderException.ToString());
                }
            }
                        
            catch(Exception ex)
            {
                Trace.TraceError(ex.ToString());
                throw;
            }

        }

        private static void InitializeContainer()
        {
            _serviceContainer = (IServiceContainer)AppDomain.CurrentDomain.GetData("LinFu.Ioc.ServiceContainer");
            //Check to see if there already is an service container present in the application domain 
            if (_serviceContainer == null)
            {
                
                _serviceContainer = new ServiceContainer();
              

                
                
                //Load up the default services
                var directory = Path.GetDirectoryName(new Uri(typeof(ServiceLocator).Assembly.CodeBase).LocalPath);
                var loader = new ContainerLoader();

                //Remove the action that loads the host assembly
                //This is because plugins are not loaded for the host assembly
                loader.QueuedActions.Clear();

                var thisAssembly = string.Format("{0}*.dll", typeof(ServiceLocator).Assembly.GetName().Name);
                if (thisAssembly == "CoreEx.Services*.dll")
                {
                    loader.LoadDirectory(directory, "CoreEx.Common*.*");
                    loader.LoadDirectory(directory, "CoreEx.Services*.*");
                }
                else
                    loader.LoadDirectory(directory,thisAssembly);


                
                loader.LoadInto(_serviceContainer);               
                
                //loader.DirectoryLister = _serviceContainer.GetService<IDirectoryListing>("DefaultDirectoryLister");                
                loader.LoadDirectory(directory, "*.dll");
                loader.LoadInto(_serviceContainer);


                //var weaveTargetDirectoryLister = _serviceContainer.GetService<IDirectoryListing>("WeaveTargetDirectoryLister");
                //var weaveTargets = weaveTargetDirectoryLister.GetFiles(directory, "*.dll");
                //loader.AssemblyLoader = _serviceContainer.GetService<IAssemblyLoader>("WeavedAssemblyLoader");
                //foreach (var weaveTarget in weaveTargets)
                //{
                //    loader.LoadFile(weaveTarget);
                //}
                //loader.LoadInto(_serviceContainer);                                
            }
            else
            {
                //Determine if the CoreEx assemblies has been loaded into an existing container
                if (_serviceContainer.AvailableServices.Where(s => s.ServiceType.Namespace.Contains("CoreEx")).Count() == 0)
                {
                    var directory = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
                    _serviceContainer.LoadFrom(directory, "*CoreEx*.dll");
                }
            }



            _serviceContainer = new ServiceContainerInvokeWrapper(_serviceContainer);
        }


        public static IServiceContainer Container
        {
            get
            {
                return _serviceContainer;
            }
        }

    }
}